package com.zhuangjie.rider.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhaungjie.base.conduit.TypeR;
import com.zhaungjie.base.utils.PropertiesCopyUtils.PropertiesCopy;
import com.zhuangjie.base.dto.page.PageDTO;
import com.zhuangjie.base.vo.PageVO;
import com.zhuangjie.mvc.future.ContextAwareExecutor;
import com.zhuangjie.mvc.helper.GeoHelper.Coordinate;
import com.zhuangjie.mvc.helper.GeoHelper.GeoCoordinateUtils;
import com.zhuangjie.mvc.helper.GeoHelper.GeoCoordinates;
import com.zhuangjie.mvc.helper.GeoHelper.process.GeoConvert;
import com.zhuangjie.order.dto.RiderLocationUpdateDTO;
import com.zhuangjie.order.entity.DeliveryInfo;
import com.zhuangjie.order.pojo.DeliveryInfoForRider;
import com.zhuangjie.order.pojo.RiderDeliveryFeeForRiderOrderAccounting;
import com.zhuangjie.order.vo.OrderDetailForDeliveryOrderDetailVO;
import com.zhuangjie.order.pojo.RiderLocation;
import com.zhuangjie.rabbit.send.wrap.MQHelper;
import com.zhuangjie.redis.helper.RedisEnhanceOperationHelper;
import com.zhuangjie.redis.helper.RedisGeoHelper;
import com.zhuangjie.rider.constant.DeliveryOrderConstant;
import com.zhuangjie.rider.constant.DeliveryOrderSystemDispatchConstant;
import com.zhuangjie.rider.constant.RiderGeoInfoConstant;
import com.zhuangjie.rider.dto.CreateDeliveryOrderDTO;
import com.zhuangjie.rider.dto.NearbyDeliveryOrderQueryDTO;
import com.zhuangjie.rider.entity.DeliveryOrder;
import com.zhuangjie.rider.enums.*;
import com.zhuangjie.rider.feign.OrderFeignService;
import com.zhuangjie.rider.feign.ShopFeignService;
import com.zhuangjie.rider.helper.DispatchIntervalProtection;
import com.zhuangjie.rider.helper.RiderModuleTokenDataProvider;
import com.zhuangjie.rider.helper.ServiceHelper;
import com.zhuangjie.rider.lock.DeliveryOrderLock;
import com.zhuangjie.rider.mapper.DeliveryOrderMapper;
import com.zhuangjie.rider.mq.producer.event.DeliveryOrderEvent;
import com.zhuangjie.rider.mq.producer.structure.DeliveryOrderMQStructure;
import com.zhuangjie.rider.pojo.DeliveryOrderDispatchReferenceInfo;
import com.zhuangjie.rider.pojo.DeliveryOrderInfoForNoticeUser;
import com.zhuangjie.rider.pojo.RechargeableDeliveryOrderGenericQueryCondition;
import com.zhuangjie.rider.pojo.ShopUserCenterPoint;
import com.zhuangjie.rider.service.DeliveryOrderService;
import com.zhuangjie.rider.service.RiderService;
import com.zhuangjie.rider.utils.DeliveryCostCalculator;
import com.zhuangjie.rider.vo.*;
import com.zhuangjie.rider.vo.PathPlanningVO.DinersForMap;
import com.zhuangjie.rider.vo.PathPlanningVO.PathPlanningResultBuilder;
import com.zhuangjie.rider.vo.PathPlanningVO.ShopForMap;
import com.zhuangjie.rider.ws.put.RiderWSPut;
import com.zhuangjie.shop.helper.ShopModuleTokenDataProvider;
import com.zhuangjie.shop.vo.ShopForRider;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author zhuangjie
 * @since 2023-12-26
 */
@Service
@Slf4j
public class DeliveryOrderServiceImpl extends ServiceImpl<DeliveryOrderMapper, DeliveryOrder> implements DeliveryOrderService {

    @Autowired
    private OrderFeignService orderFeignService;

    @Autowired
    private ShopFeignService shopFeignService;

    @Autowired
    private RedisGeoHelper redisGeoHelper;


    @Autowired
    private ContextAwareExecutor contextAwareExecutor;

    @Autowired
    private RiderService riderService;

    @Autowired
    private MQHelper mqHelper;

    @Autowired
    private RiderWSPut riderWSPut;

    @Autowired
    private Redisson redisson;

    @Autowired
    private DispatchIntervalProtection dispatchIntervalProtection;

    @Autowired
    private RedisEnhanceOperationHelper redisEnhanceOperationHelper;




    @Override
    public void tryCreateDeliveryOrder(CreateDeliveryOrderDTO createDeliveryOrderDTO) throws Exception {
        // 获取要创建订单的相关信息
        CompletableFuture<DeliveryInfoForRider> deliveryInfoCompletableFuture = CompletableFuture.supplyAsync(() -> {
            try {
                return TypeR.extract(orderFeignService.queryForCreateDeliveryOrder(createDeliveryOrderDTO.getOrderId()));
            } catch (Exception e) {
                throw new RuntimeException("无法为创建配送单查询查询到DeliveryInfo（用户地址信息）");
            }
        }, contextAwareExecutor);
        Long shopId = ShopModuleTokenDataProvider.getShopId();
        CompletableFuture<ShopForRider> shopForRiderCompletableFuture = CompletableFuture.supplyAsync(() -> {
            TypeR<ShopForRider> shopAddress = shopFeignService.getShopDeliveryInfo(shopId);
            try {
                return shopAddress.extract();
            } catch (Exception e) {
                throw new RuntimeException("无法为创建配送单查询到店铺信息");
            }
        });
        CompletableFuture<Boolean> isExistDeliveryOrderCompletableFuture = CompletableFuture.supplyAsync(() ->
                this.count(Wrappers.lambdaQuery(DeliveryOrder.class).eq(DeliveryOrder::getOrderId, createDeliveryOrderDTO.getOrderId())) > 0);
        CompletableFuture.allOf(shopForRiderCompletableFuture, deliveryInfoCompletableFuture).join();
        if (isExistDeliveryOrderCompletableFuture.get()) {
            throw new RuntimeException("订单已经存在配送单");
        }
        try {
            DeliveryInfoForRider deliveryInfoForRider = deliveryInfoCompletableFuture.get();
            ShopForRider shopForRider = shopForRiderCompletableFuture.get();
            // 创建DeliveryOrder对象的实例
            DeliveryOrder deliveryOrder = new DeliveryOrder();

            // 设置属性值
            deliveryOrder.setOrderId(createDeliveryOrderDTO.getOrderId());
            deliveryOrder.setDeliveryState(DeliveryState.WAITING_FOR_RIDER);
            deliveryOrder.setIncomeState(IncomeState.WAIT_TO_FINISH);
            // deliveryOrder.setIncome(calculateIncome(shopForRider, deliveryInfoForRider));
            // 这里可以在actualDeliveryFee基础上加，但多出的部分平台要出
            deliveryOrder.setIncome(createDeliveryOrderDTO.getActualDeliveryFee());
            deliveryOrder.setShopId(shopId);

            deliveryOrder.setDesignatedDeliveryTime(
                    ServiceHelper.isValidDesignatedDeliveryTime(deliveryInfoForRider.getEstimatedDeliveryTime(), deliveryInfoForRider.getDeliveryDuration())
                            ? deliveryInfoForRider.getDesignatedDeliveryTime()
                            : null); // 取消定时单标志
            deliveryOrder.setUserId(deliveryInfoForRider.getUserId());
            deliveryOrder.setDeliveryMethod(shopForRider.getDeliveryMethod());
            // TODO 使用定时任务随时间变长当没有骑手接单时，范围变大，直到允许的最大值
            deliveryOrder.setVisibleRange(DeliveryOrderConstant.VISIBLE_RANGE);
            deliveryOrder.setDeliveryMethod(shopForRider.getDeliveryMethod());
            deliveryOrder.setCode(deliveryInfoForRider.getCurrentOrderShopCode());
//            int deliveryDuration = (int) Duration.between(deliveryInfoForRider.getOrderCreateTime(), deliveryInfoForRider.getEstimatedDeliveryTime()).toMinutes();
            deliveryOrder.setDeliveryDuration(deliveryInfoForRider.getDeliveryDuration());
            // 看是否有效指定了配送时间
//            deliveryOrder.setDeliveryTime( isValidDesignatedDeliveryTime?deliveryInfoForRider.getDesignatedDeliveryTime():LocalDateTime.now().plusMinutes(deliveryInfoForRider.getDeliveryDuration()));
            // 设置店铺相关信息
            deliveryOrder.setShopPhone(shopForRider.getPhone());
            deliveryOrder.setShopName(shopForRider.getShopName());
            deliveryOrder.setShopAddressDescribe(shopForRider.getAddressDescribe());
            deliveryOrder.setShopLongitude(shopForRider.getLongitude());
            deliveryOrder.setShopLatitude(shopForRider.getLatitude());
            deliveryOrder.setShopCityCode(shopForRider.getCityCode());

            // 设置收货人相关信息
            deliveryOrder.setConsigneeFullname(deliveryInfoForRider.getConsignee());
            deliveryOrder.setConsigneePhone(deliveryInfoForRider.getPhone());
            deliveryOrder.setConsigneeLongitude(deliveryInfoForRider.getLongitude());
            deliveryOrder.setConsigneeLatitude(deliveryInfoForRider.getLatitude());
            deliveryOrder.setConsigneeAddressName(deliveryInfoForRider.getDetailAddress());
            deliveryOrder.setConsigneeAddressDescribe(deliveryInfoForRider.getSpecificAddress());
            deliveryOrder.setConsigneeCityCode(deliveryInfoForRider.getCityCode());
            // 寻找附近的骑手
            GeoResult<RedisGeoCommands.GeoLocation<String>> nearRider = this.findNearRider(shopForRider.getLongitude(), shopForRider.getLatitude(), deliveryOrder);
            deliveryOrder.setAssignRiderId(nearRider != null ? getRiderId(nearRider) : AssignState.UNASSIGNED);
            this.save(deliveryOrder);
            if (nearRider == null) return;
            // 发送MQ解锁上述的Assigning由AssignState.ASSIGNED -> AssignState.UNASSIGNED
            mqHelper.send(DeliveryOrderMQStructure.EXCHANGE_NAME, DeliveryOrderEvent.ORDER_ACCEPTANCE_TIMEOUT, deliveryOrder.getId());
            // 异步通知骑手接单
            CompletableFuture.runAsync(() -> {
                // - 查询骑手（riderId）的位置
                GeoCoordinates nearRiderGeo = new GeoCoordinates(nearRider.getContent().getPoint().getX(), nearRider.getContent().getPoint().getY());
                // - 通知骑手
                SystemDispatchNearbyDeliveryOrder systemDispatchNearbyDeliveryOrder = this.computeChangeToNearbyDeliveryOrder(nearRiderGeo, deliveryOrder, SystemDispatchNearbyDeliveryOrder.class);
                systemDispatchNearbyDeliveryOrder.setLockTime(DeliveryOrderConstant.ORDER_ACCEPTANCE_TIMEOUT);
                riderWSPut.putDeliveryRider(systemDispatchNearbyDeliveryOrder, String.valueOf(deliveryOrder.getAssignRiderId()));
            });

        } catch (Exception e) {
            throw new RuntimeException("无法创建配送单");
        }


    }

    /**
     * 寻找适合的的骑手进行派单
     *
     * @param longitude
     * @param latitude
     * @param deliveryOrder
     * @return
     */
    private GeoResult<RedisGeoCommands.GeoLocation<String>> findNearRider(Double longitude, Double latitude, DeliveryOrder deliveryOrder) {
        GeoResults<RedisGeoCommands.GeoLocation<String>> nearbyRider = redisGeoHelper.findNearby(RiderGeoInfoConstant.RIDER_GEO_INFO_KEY, longitude, latitude, DeliveryOrderSystemDispatchConstant.SYSTEM_DISPATCH_RADIUS, DeliveryOrderSystemDispatchConstant.MAX_ANALYZE_COUNT);
        if (nearbyRider == null || nearbyRider.getContent() == null || nearbyRider.getContent().isEmpty()) return null;
        List<GeoResult<RedisGeoCommands.GeoLocation<String>>> content = nearbyRider.getContent().stream().filter(item -> CheckValidity(item)).sorted(Comparator.comparingDouble(o -> o.getDistance().getValue())).collect(Collectors.toList());
        Map<Long, GeoResult<RedisGeoCommands.GeoLocation<String>>> itemMap = content.stream().collect(Collectors.toMap(item -> getRiderId(item), item -> item));
        List<Long> riderIds = content.stream().map(item -> Long.valueOf(String.valueOf(item.getContent().getName()))).collect(Collectors.toList());
        // 开始分析派给哪个骑手
        // 过滤不可接单的骑手(仍然有序)
        riderIds = filterUnavailableRiders(riderIds);
        if (riderIds.isEmpty()) return null;
        // 查询这些骑手接的暂未到店的配送单列表
        Map<Long, List<DeliveryOrder>> canAcceptOrderRiderInProgressDeliveryOrderMap = this.findRidersNotArrivedStoreDeliveryOrder(riderIds);
        while (true) {
            GeoResult<RedisGeoCommands.GeoLocation<String>> mostAppropriateRider = getMostAppropriateRider(deliveryOrder, itemMap, riderIds, canAcceptOrderRiderInProgressDeliveryOrderMap);
            if (mostAppropriateRider == null) {
                break;
            }
            // 尝试加保护（当失败时）
            Long checkedRiderId = getRiderId(mostAppropriateRider);
            if (dispatchIntervalProtection.tryConstructProtection(checkedRiderId)) {
                return mostAppropriateRider;
            }
            // 当前失败，排除它，进行下一次的选择
            riderIds.remove(checkedRiderId);
            canAcceptOrderRiderInProgressDeliveryOrderMap.remove(checkedRiderId);
            // 当不能再进行下次选择了，就不派了
            if (riderIds.isEmpty()) {
                break;
            }
        }
        return null;
    }

    /**
     * 找到最合适骑手
     *
     * @param deliveryOrder                                 交货订单
     * @param itemMap                                       项目映射
     * @param riderIds                                      骑手id
     * @param canAcceptOrderRiderInProgressDeliveryOrderMap
     * @return {@link GeoResult}<{@link RedisGeoCommands.GeoLocation}<{@link String}>>
     */
    private GeoResult<RedisGeoCommands.GeoLocation<String>> getMostAppropriateRider(DeliveryOrder deliveryOrder, Map<Long, GeoResult<RedisGeoCommands.GeoLocation<String>>> itemMap, List<Long> riderIds, Map<Long, List<DeliveryOrder>> canAcceptOrderRiderInProgressDeliveryOrderMap) {
        if (riderIds.isEmpty()) {
            return null;
        }
        Map<Long, List<DeliveryOrder>> hasDeliveryOrderListMap = new HashMap<>();
        for (Map.Entry<Long, List<DeliveryOrder>> entry : canAcceptOrderRiderInProgressDeliveryOrderMap.entrySet()) {
            List<DeliveryOrder> deliveryOrders = entry.getValue();
            if (deliveryOrders != null && !deliveryOrders.isEmpty()) {
                hasDeliveryOrderListMap.put(entry.getKey(), deliveryOrders);
            }
        }
        // content = content.stream().filter(_item -> canAcceptOrderRiderInProgressDeliveryOrderMap.get(getRiderId(_item)) != null).collect(Collectors.toList());
        // 策略：看骑手手上的单子的位置
        // 下列名词说明：“一定区域店铺”指的当前要进行派单的配送单不在骑手已接的所有配送单店铺的中心发出的范围内
        //             "一定区域用户" 同上
        //      优先级一：派给有同店铺同用户的
        //      优先级二：满足在一定区域店铺同一用户的
        //         优先级2.1：满足在一定区域内店铺与一定区域内用户的有单骑手
        //         优先级2.2：满足在一定区域内店铺的最近且无单骑手

        // - 实现优先级2.2
        if (hasDeliveryOrderListMap.isEmpty()) {
            // 这里肯定有无单骑手(riderIds不为空，前面已经判断过)，获取最近的派单
            return itemMap.get(riderIds.get(0));
        }
        // - 实现优先级一
        // 看是否有骑手手上是否有与当前的配送单是否同店铺同用户的
        for (Long riderId : riderIds) {
            List<DeliveryOrder> deliveryOrders = hasDeliveryOrderListMap.get(riderId);
            if (deliveryOrders == null || deliveryOrders.isEmpty()) continue;
            for (DeliveryOrder currentDeliveryOrder : deliveryOrders) {
                if (currentDeliveryOrder.getShopId().equals(deliveryOrder.getShopId()) && currentDeliveryOrder.getUserId().equals(deliveryOrder.getUserId())) {
                    return itemMap.get(riderId);
                }
            }
        }
        // 后续优先级可能需要的操作-过滤掉不在一定区域店铺一定区域用户
        Map<Long, ShopUserCenterPoint> shopUserCenterPointMap = this.computeShopUserCenterPoint(hasDeliveryOrderListMap);
        List<DeliveryOrderDispatchReferenceInfo> meetDeliveryOrderDispatchReferenceInfoList = shopUserCenterPointMap.entrySet().stream()
                .map(entry -> {
                    ShopUserCenterPoint shopUserCenterPoint = entry.getValue();
                    double shopCenterPointDistance = GeoCoordinateUtils.calculateDistance(deliveryOrder.getShopLongitude(), deliveryOrder.getShopLatitude(), shopUserCenterPoint.getShopCenterPoint().getLongitude(), shopUserCenterPoint.getShopCenterPoint().getLatitude());
                    double userCenterPointDistance = GeoCoordinateUtils.calculateDistance(deliveryOrder.getConsigneeLongitude(), deliveryOrder.getConsigneeLatitude(), shopUserCenterPoint.getUserCenterPoint().getLongitude(), shopUserCenterPoint.getUserCenterPoint().getLatitude());
                    return new DeliveryOrderDispatchReferenceInfo(entry.getKey(), shopCenterPointDistance, userCenterPointDistance);
                })
                .filter(entry -> entry.getShopDistance() <= DeliveryOrderSystemDispatchConstant.SHOP_CONCENTRATE_RADIUS && entry.getUserDistance() <= DeliveryOrderSystemDispatchConstant.DELIVERY_USER_CONCENTRATE_RADIUS)
                .sorted((o1, o2) -> o1.getShopDistance() == o2.getShopDistance() ? Double.compare(o1.getUserDistance(), o2.getUserDistance()) : Double.compare(o1.getShopDistance(), o2.getShopDistance()))
                .collect(Collectors.toList());
        // 当没有在一定区域店铺一定区域用户
        if (meetDeliveryOrderDispatchReferenceInfoList == null || meetDeliveryOrderDispatchReferenceInfoList.isEmpty()) {
            for (Long riderId : riderIds) {
                List<DeliveryOrder> deliveryOrders = canAcceptOrderRiderInProgressDeliveryOrderMap.get(riderId);
                if (deliveryOrders == null || deliveryOrders.isEmpty()) {
                    return itemMap.get(riderId);
                }
            }
            return null;
        }
        // - 实现优先级二: 同用户优先
        for (DeliveryOrderDispatchReferenceInfo deliveryOrderDispatchReferenceInfo : meetDeliveryOrderDispatchReferenceInfoList) {
            Long currentRiderId = deliveryOrderDispatchReferenceInfo.getRiderId();
            List<DeliveryOrder> deliveryOrders = hasDeliveryOrderListMap.get(currentRiderId);
            // 看持有的配送单中是否有当前要派发的配送单用户id是否一样
            for (DeliveryOrder currentDeliveryOrder : deliveryOrders) {
                if (currentDeliveryOrder.getUserId().equals(deliveryOrder.getUserId())) {
                    return itemMap.get(currentRiderId);
                }
            }
        }
        // - 满足在一定区域内店铺与一定区域内用户的有单骑手（最近）
        return itemMap.get(meetDeliveryOrderDispatchReferenceInfoList.get(0).getRiderId());
    }

    private static Long getRiderId(GeoResult<RedisGeoCommands.GeoLocation<String>> geoLocationGeoResult) {
        return Long.valueOf(String.valueOf(geoLocationGeoResult.getContent().getName()));
    }

    /**
     * 筛选不可用附加条款
     *
     * @param riderIds 骑手id
     */
    private List<Long> filterUnavailableRiders(List<Long> riderIds) {
        if (riderIds == null || riderIds.isEmpty()) {
            return null;
        }
        // 过滤掉在保护中的（这里）
        riderIds = dispatchIntervalProtection.filterProtection(riderIds);
        if (riderIds.isEmpty()) return new ArrayList<>();
        // 过滤掉接单量达到最大接单量或不在线的的骑手（这里过滤后无序）
        List<Long> unorderedRiderIds = riderService.filterUnavailableRiders(riderIds, RiderWorkState.ONLINE, DeliveryOrderState.DELIVERED_TO_USER);
        // 使保持有序
        return riderIds.stream().filter(riderId -> unorderedRiderIds.contains(riderId)).collect(Collectors.toList());
    }

    private boolean CheckValidity(GeoResult<RedisGeoCommands.GeoLocation<String>> item) {
        return item != null && item.getContent() != null && item.getContent().getName() != null && item.getContent().getPoint() != null;
    }


    private Map<Long, ShopUserCenterPoint> computeShopUserCenterPoint(Map<Long, List<DeliveryOrder>> deliveryOrderListMap) {
        if (deliveryOrderListMap == null || deliveryOrderListMap.isEmpty()) {
            return new HashMap<>();
        }
        return deliveryOrderListMap.keySet().stream().collect(Collectors.toMap(riderId -> riderId, riderId -> {
            ShopUserCenterPoint shopUserCenterPoint = new ShopUserCenterPoint();
            List<DeliveryOrder> deliveryOrders = deliveryOrderListMap.get(riderId);
            List<Coordinate> currentUserGeoList = deliveryOrders.stream().map(deliveryOrder -> new Coordinate(deliveryOrder.getConsigneeLongitude(), deliveryOrder.getConsigneeLatitude())).collect(Collectors.toList());
            List<Coordinate> currentShopGeoList = deliveryOrders.stream().map(deliveryOrder -> new Coordinate(deliveryOrder.getShopLongitude(), deliveryOrder.getShopLatitude())).collect(Collectors.toList());
            shopUserCenterPoint.setShopCenterPoint(GeoCoordinateUtils.getCenterPoint(currentShopGeoList));
            shopUserCenterPoint.setUserCenterPoint(GeoCoordinateUtils.getCenterPoint(currentUserGeoList));
            return shopUserCenterPoint;
        }));
    }

    /**
     * 交货订单列表后处理
     * (可以使得在骑手端显示定时订单为其它配送单)
     *
     * @param list 列表
     * @return {@link List}<{@link T}>
     */
    public <T extends DeliveryOrder> List<T> deliveryOrderListPostProcess(List<T> list) {
        if (list == null || list.isEmpty()) return new ArrayList<>();
        for (T nearbyDeliveryOrder : list) {
            if (!ServiceHelper.isValidDesignatedDeliveryTime(nearbyDeliveryOrder.getDesignatedDeliveryTime(), nearbyDeliveryOrder.getDeliveryDuration())) {
                nearbyDeliveryOrder.setDesignatedDeliveryTime(null);
            }
        }
        return list;
    }

    @Override
    public PageVO<NearbyDeliveryOrder> findNearbyDeliveryOrders(NearbyDeliveryOrderQueryDTO nearbyDeliveryOrderQueryDTO) {
        Page<NearbyDeliveryOrder> nearbyDeliveryOrdersPage = new Page<>(nearbyDeliveryOrderQueryDTO.getCurrentPage(), nearbyDeliveryOrderQueryDTO.getPageSize());
        // 通用的分配订单查询条件
        RechargeableDeliveryOrderGenericQueryCondition genericQueryCondition = new RechargeableDeliveryOrderGenericQueryCondition();
        this.baseMapper.findNearbyDeliveryOrders(nearbyDeliveryOrderQueryDTO, genericQueryCondition, nearbyDeliveryOrdersPage);
        // 获取查询结果
        List<NearbyDeliveryOrder> nearbyDeliveryOrderList = nearbyDeliveryOrdersPage.getRecords();
        // 在抢单时，当定时单已经超过该时间时，让这个定时效果在骑手端失效（显示为普通配送单）- DesignatedDeliveryTime让其为null即可
        deliveryOrderListPostProcess(nearbyDeliveryOrderList);
        // 计算元素对象的某些属性
        GeoCoordinates riderGeoCoordinates = new GeoCoordinates();
        // 进行计算距离
        computeChangeToNearbyDeliveryOrder(riderGeoCoordinates, nearbyDeliveryOrderList, NearbyDeliveryOrder.class);
        return new PageVO(nearbyDeliveryOrdersPage);
    }

    public <T extends DeliveryOrder, C extends NearbyDeliveryOrder> List<C> computeChangeToNearbyDeliveryOrder(GeoCoordinates riderGeo, List<T> deliveryOrders, Class<C> clazz) {
        return deliveryOrders.stream().map(deliveryOrder -> {
            C nearbyDeliveryOrder = clazz.isInstance(deliveryOrder) ? (C) deliveryOrder : PropertiesCopy.type(DeliveryOrder.class, clazz).produce(deliveryOrder);
            if (nearbyDeliveryOrder.getShopDistance() == null) {
                Double riderToShopDistance = GeoCoordinateUtils.calculateDistance(riderGeo.getLongitude(), riderGeo.getLatitude(), nearbyDeliveryOrder.getShopLongitude(), nearbyDeliveryOrder.getShopLatitude());
                nearbyDeliveryOrder.setShopDistance(riderToShopDistance);
            }
            if (nearbyDeliveryOrder.getShopToUserDistance() == null) {
                Double shopToUserDistance = GeoCoordinateUtils.calculateDistance(nearbyDeliveryOrder.getShopLongitude(), nearbyDeliveryOrder.getShopLatitude(), nearbyDeliveryOrder.getConsigneeLongitude(), nearbyDeliveryOrder.getConsigneeLatitude());
                nearbyDeliveryOrder.setShopToUserDistance(shopToUserDistance);
            }
            return nearbyDeliveryOrder;
        }).collect(Collectors.toList());
    }

    public <T extends DeliveryOrder, C extends NearbyDeliveryOrder> C computeChangeToNearbyDeliveryOrder(GeoCoordinates riderGeo, T deliveryOrder, Class<C> clazz) {
        List<C> nearbyDeliveryOrders = this.computeChangeToNearbyDeliveryOrder(riderGeo, Arrays.asList(deliveryOrder), clazz);
        return nearbyDeliveryOrders.get(0);
    }


    /**
     * 查询多个骑手未到店接单的配送单列表
     *
     * @param riderIds
     * @return
     */
    @Override
    public Map<Long, List<DeliveryOrder>> findRidersNotArrivedStoreDeliveryOrder(List<Long> riderIds) {
        LambdaQueryWrapper<DeliveryOrder> queryRidersNotArrivedStoreDeliveryOrderWrapper = Wrappers.lambdaQuery(DeliveryOrder.class)
                .in(DeliveryOrder::getRiderId, riderIds)
                .lt(DeliveryOrder::getDeliveryState, DeliveryOrderState.RIDER_ARRIVED_STORE.getValue());
        List<DeliveryOrder> ridersNotArrivedStoreDeliveryOrderList = this.list(queryRidersNotArrivedStoreDeliveryOrderWrapper);
        // 将ridersNotArrivedStoreDeliveryOrderList根据riderId进行分组组装为Map
        Map<Long, List<DeliveryOrder>> result = new HashMap<>();
        if (ridersNotArrivedStoreDeliveryOrderList == null || ridersNotArrivedStoreDeliveryOrderList.isEmpty()) {
            return result;
        }
        for (DeliveryOrder deliveryOrder : ridersNotArrivedStoreDeliveryOrderList) {
            Long currentRiderId = deliveryOrder.getRiderId();
            List<DeliveryOrder> deliveryOrders = result.get(currentRiderId);
            if (deliveryOrders == null) result.put(currentRiderId, deliveryOrders = new ArrayList<>());
            deliveryOrders.add(deliveryOrder);
        }
        return result;
    }

    @Override
    public void acceptSystemDispatchDeliveryOrder(Long deliveryOrderId) {
        RLock lock = redisson.getLock(DeliveryOrderLock.getDeliveryOrderOperationLock(deliveryOrderId));
        lock.lock();
        try {
            Long currentRiderId = RiderModuleTokenDataProvider.getCurrentRiderId();
            LambdaUpdateWrapper<DeliveryOrder> acceptSystemDispatchDeliveryOrderWrapper = getGenericObtainDeliveryOrderWrapper(deliveryOrderId);
            acceptSystemDispatchDeliveryOrderWrapper
                    .eq(DeliveryOrder::getAssignRiderId, currentRiderId)
                    .set(DeliveryOrder::getAssignRiderId, AssignState.UNASSIGNED);
            if (!this.update(acceptSystemDispatchDeliveryOrderWrapper)) {
                throw new RuntimeException("接受系统派单失败， deliveryOrderId: " + deliveryOrderId);
            }
            orderStateChangeNoticeUser(deliveryOrderId);
        } finally {
            lock.unlock();
        }

    }

//    private LocalDateTime computeDeliveryOrderDeliveryTime(Long deliveryOrderId) {
//
//    }

    /**
     * 获取通用获取交货订单Wrapper
     *
     * @param deliveryOrderId 交货订单id
     * @return {@link LambdaUpdateWrapper}<{@link DeliveryOrder}>
     */
    public LambdaUpdateWrapper<DeliveryOrder> getGenericObtainDeliveryOrderWrapper(Long deliveryOrderId) {
        DeliveryOrder deliveryOrder = this.getById(deliveryOrderId);
        if (deliveryOrder == null) {
            throw new RuntimeException("配送单不存在！");
        }
        LocalDateTime deliveryTime = deliveryOrder.getDesignatedDeliveryTime();
        boolean isValidDesignatedDeliveryTime = ServiceHelper.isValidDesignatedDeliveryTime(deliveryOrder.getDesignatedDeliveryTime(), deliveryOrder.getDeliveryDuration());
        if (!isValidDesignatedDeliveryTime) {
            deliveryTime = LocalDateTime.now().plusMinutes(deliveryOrder.getDeliveryDuration());
        }

        Long currentRiderId = RiderModuleTokenDataProvider.getCurrentRiderId();
        LambdaUpdateWrapper<DeliveryOrder> grabbingOrderWrapper = Wrappers.lambdaUpdate(DeliveryOrder.class)
                .eq(DeliveryOrder::getId, deliveryOrderId)
                .eq(DeliveryOrder::getDeliveryState, DeliveryOrderState.PENDING_PICKUP.getValue())
                .set(DeliveryOrder::getDeliveryState, DeliveryOrderState.RIDER_RECEIVED_ORDER.getValue())
                .set(DeliveryOrder::getRiderId, currentRiderId)
                .set(DeliveryOrder::getDesignatedDeliveryTime, isValidDesignatedDeliveryTime ? deliveryTime : null)
                .set(DeliveryOrder::getDeliveryTime, deliveryTime);
        return grabbingOrderWrapper;
    }

    @Override
    public void grabbingOrder(Long deliveryOrderId) {
        RLock lock = redisson.getLock(DeliveryOrderLock.getDeliveryOrderOperationLock(deliveryOrderId));
        lock.lock();
        try {
            LambdaUpdateWrapper<DeliveryOrder> grabbingOrderWrapper = getGenericObtainDeliveryOrderWrapper(deliveryOrderId);
            grabbingOrderWrapper.isNull(DeliveryOrder::getAssignRiderId);
            boolean isGrabbingOrderSuccess = this.update(grabbingOrderWrapper);
            if (!isGrabbingOrderSuccess) {
                throw new RuntimeException("订单已被抢了~");
            }
            orderStateChangeNoticeUser(deliveryOrderId);
        } finally {
            lock.unlock();
        }
    }

    /**
     * 订单-配送订单状态改变通知用户
     * @param deliveryOrderId
     */
    public void orderStateChangeNoticeUser(Long deliveryOrderId) {
        DeliveryOrderInfoForNoticeUser deliveryOrderInfo = this.baseMapper.getDeliveryOrderInfoForNoticeUser(deliveryOrderId);
        // 这里不进行TypeR.capture 来看是否成功，不成功问题也不大
        orderFeignService.orderStateChange(deliveryOrderInfo.getUserId(), deliveryOrderInfo.getOrderId());
    }


    /**
     * 骑手到店
     *
     * @param deliveryOrderId 交货订单id
     * @return {@link Integer}
     */
    @Override
    public Integer reportToShop(Long deliveryOrderId) {
        Long currentRiderId = RiderModuleTokenDataProvider.getCurrentRiderId();
        RLock lock = redisson.getLock(DeliveryOrderLock.getDeliveryOrderOperationLock(deliveryOrderId));
        lock.lock();
        try {
            LambdaUpdateWrapper<DeliveryOrder> grabbingOrderWrapper = Wrappers.lambdaUpdate(DeliveryOrder.class)
                    .eq(DeliveryOrder::getId, deliveryOrderId)
                    .eq(DeliveryOrder::getDeliveryState, DeliveryOrderState.RIDER_RECEIVED_ORDER.getValue())
                    .eq(DeliveryOrder::getRiderId, currentRiderId)
                    .set(DeliveryOrder::getDeliveryState, DeliveryOrderState.RIDER_ARRIVED_STORE.getValue());
            boolean toShopSuccess = this.update(grabbingOrderWrapper);
            if (!toShopSuccess) {
                throw new RuntimeException("订单状态可能已经改变！");
            }
            CompletableFuture.allOf(
                    CompletableFuture.runAsync(() -> {
                        // 添加间隔（redis）
                        Instant expireTimestamp = Instant.now().plus(DeliveryOrderConstant.TO_SHOP_PICKING_INTERVAL, ChronoUnit.SECONDS);
                        redisEnhanceOperationHelper.luaImplHashPutAndExpire(DeliveryOrderConstant.getToShopPickingIntervalControlKey(currentRiderId), String.valueOf(deliveryOrderId), expireTimestamp, DeliveryOrderConstant.TO_SHOP_PICKING_INTERVAL);
                    }),
                    CompletableFuture.runAsync(() -> {
                        // 通知用户状态已经改变
                        orderStateChangeNoticeUser(deliveryOrderId);
                    })
            ).join();
            // 前端需要等待一定的时长才能进行后续的操作
            return DeliveryOrderConstant.TO_SHOP_PICKING_INTERVAL;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public CompletedQuantityStatisticsVO completedQuantityStatistics(LocalDateTime startTime, LocalDateTime endTime) {
        return this.baseMapper.completedQuantityStatistics(RiderModuleTokenDataProvider.getCurrentRiderId(), DeliveryOrderState.DELIVERED_TO_USER.getValue(), startTime, endTime);
    }

    @Override
    public PageVO<WaitPickingDeliveryOrder> riderWaitPickingPage(PageDTO pageDTO) {
        Page<WaitPickingDeliveryOrder> page = new Page<>(pageDTO.getCurrentPage(), pageDTO.getPageSize());
        Long riderId = RiderModuleTokenDataProvider.getCurrentRiderId();
        this.baseMapper.queryRiderWaitPickingDeliverOrders(page, riderId, DeliveryOrderState.RIDER_RECEIVED_ORDER.getValue(), DeliveryOrderState.RIDER_ARRIVED_STORE.getValue());
        List<WaitPickingDeliveryOrder> list = page.getRecords();
        // 获取配送单的canPickUpTimeStamp(当有值时，说明需要等到这个时间戳才能点取餐)
        List<String> deliveryOrderIds = list.stream().map(item -> String.valueOf(item.getId())).collect(Collectors.toList());
        List<Long> hashValues = redisEnhanceOperationHelper.getHashValues(DeliveryOrderConstant.getToShopPickingIntervalControlKey(riderId), deliveryOrderIds, Long.class);
        for (int i = 0; i < list.size(); i++) {
            WaitPickingDeliveryOrder waitPickingDeliveryOrder = list.get(i);
            boolean isExpire = hashValues.get(i) == null || new Date(hashValues.get(i)).getTime() <= System.currentTimeMillis();
            waitPickingDeliveryOrder.setCanPickUpTimeStamp(isExpire ? null : hashValues.get(i));
        }

        return new PageVO(page);
    }


    @Override
    @GlobalTransactional
    public void confirmMealPickup(Long deliveryOrderId) {
        Long currentRiderId = RiderModuleTokenDataProvider.getCurrentRiderId();
        RLock lock = redisson.getLock(DeliveryOrderLock.getDeliveryOrderOperationLock(deliveryOrderId));
        lock.lock();
        try {
            // 判断是否已经可以点取餐(时间戳)
            Long timestamp = redisEnhanceOperationHelper.getHashValue(DeliveryOrderConstant.getToShopPickingIntervalControlKey(currentRiderId), String.valueOf(deliveryOrderId), Long.class);
            if (timestamp != null && System.currentTimeMillis() < timestamp) {
                throw new RuntimeException("从到店到取餐有一定时间间隔，请稍后再试");
            }
            LambdaUpdateWrapper<DeliveryOrder> confirmMealPickupUpdateWrapper = Wrappers.lambdaUpdate(DeliveryOrder.class)
                    .eq(DeliveryOrder::getId, deliveryOrderId)
                    .eq(DeliveryOrder::getRiderId, currentRiderId)
                    .eq(DeliveryOrder::getDeliveryState, DeliveryOrderState.RIDER_ARRIVED_STORE.getValue())
                    .set(DeliveryOrder::getDeliveryState, DeliveryOrderState.RIDER_PICKED_UP.getValue());
            boolean isUpdateSuccess = this.update(confirmMealPickupUpdateWrapper);
            if (!isUpdateSuccess) {
                throw new RuntimeException("确认取餐失败,状态可能已经改变！");
            }
            CompletableFuture.allOf(
                    CompletableFuture.runAsync(() -> {
                        // 更新订单Order状态为“派送中”
                        Long orderId = getOrderIdByDeliveryOrderId(deliveryOrderId);
                        try {
                            TypeR.capture(orderFeignService.updateDeliveryOrderToDelivering(orderId));
                        } catch (Exception e) {
                            throw new RuntimeException("更新订单为派送中失败！");
                        }
                    }, contextAwareExecutor),
                    // 通知用户状态已经改变
                    CompletableFuture.runAsync(() -> orderStateChangeNoticeUser(deliveryOrderId))
            ).join();

        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }

    private Long getOrderIdByDeliveryOrderId(Long deliveryOrderId) {
        LambdaQueryWrapper<DeliveryOrder> queryOrderIdWrapper = Wrappers.lambdaQuery(DeliveryOrder.class)
                .eq(DeliveryOrder::getId, deliveryOrderId)
                .select(DeliveryOrder::getOrderId);
        DeliveryOrder deliveryOrder = this.getOne(queryOrderIdWrapper);
        return deliveryOrder.getOrderId();
    }

    @Override
    @GlobalTransactional
    public void riderCompleteDelivery(Long deliveryOrderId) throws Exception {
        Long currentRiderId = RiderModuleTokenDataProvider.getCurrentRiderId();
        RLock lock = redisson.getLock(DeliveryOrderLock.getDeliveryOrderOperationLock(deliveryOrderId));
        lock.lock();
        try {
            LambdaUpdateWrapper<DeliveryOrder> confirmMealPickupUpdateWrapper = Wrappers.lambdaUpdate(DeliveryOrder.class)
                    .eq(DeliveryOrder::getId, deliveryOrderId)
                    .eq(DeliveryOrder::getRiderId, currentRiderId)
                    .eq(DeliveryOrder::getDeliveryState, DeliveryOrderState.RIDER_PICKED_UP.getValue())
                    .set(DeliveryOrder::getDeliveryState, DeliveryOrderState.DELIVERED_TO_USER.getValue());
            boolean isUpdateSuccess = this.update(confirmMealPickupUpdateWrapper);
            if (!isUpdateSuccess) {
                throw new RuntimeException("确认送达失败,状态可能已经改变！");
            }

            CompletableFuture.allOf(
                    CompletableFuture.runAsync(() -> {
                        // 将订单Order状态修改为已完成
                        // - 获取订单order的id
                        Long orderId = getOrderIdByDeliveryOrderId(deliveryOrderId);
                        // 开启模块的安全访问（内部接口安全访问要求）
                        // moduleSecurityHelper.useModuleSecurityAccess();
                        // - 修改状态  派送中 -> 已完成
                        try {
                            TypeR.extract(orderFeignService.updateDeliveryOrderToCompleted(orderId));
                        } catch (Exception e) {
                            throw new RuntimeException("订单无法改为已完成！");
                        }
                    }, contextAwareExecutor),
                    CompletableFuture.runAsync(() -> orderStateChangeNoticeUser(deliveryOrderId))

            ).join();

        } finally {
            lock.unlock();
        }
    }

    @Override
    public PageVO riderWaitDeliveryPage(PageDTO pageDTO) {
        Page<DeliveryOrder> page = new Page<>(pageDTO.getCurrentPage(), pageDTO.getPageSize());
        Long riderId = RiderModuleTokenDataProvider.getCurrentRiderId();
        this.baseMapper.queryRiderWaitDeliveryPage(page, riderId, DeliveryOrderState.RIDER_PICKED_UP.getValue());
        return new PageVO(page);
    }

    @Override
    public Set<ShopForMap> riderRoutePlanning(GeoCoordinates riderGeo) {
        LambdaQueryWrapper<DeliveryOrder> queryRiderUnfinishedDeliverOrderListWrapper = Wrappers.lambdaQuery(DeliveryOrder.class)
                .eq(DeliveryOrder::getRiderId, RiderModuleTokenDataProvider.getCurrentRiderId())
                .between(DeliveryOrder::getDeliveryState, DeliveryOrderState.RIDER_RECEIVED_ORDER.getValue(), DeliveryOrderState.RIDER_PICKED_UP.getValue());
        List<DeliveryOrder> deliveryOrders = this.baseMapper.selectList(queryRiderUnfinishedDeliverOrderListWrapper);
        if (!CollectionUtils.isNotEmpty(deliveryOrders)) return new HashSet<>();
        // 构建后面进行运算的数据结构
        PathPlanningResultBuilder pathPlanningResultBuilder = new PathPlanningResultBuilder(deliveryOrders);
        // 设置navigationSort属性
        return computeNavigationSortAttribute(riderGeo, pathPlanningResultBuilder);
    }

    @Override
    public DeliveryOrderDetailsVO deliveryOrderDetail(Long deliveryOrderId, @GeoConvert GeoCoordinates riderGeo) throws Exception {
        NearbyDeliveryOrder deliveryOrder = this.baseMapper.selectToNearbyDeliveryOrderById(deliveryOrderId);
        this.computeChangeToNearbyDeliveryOrder(riderGeo, Arrays.asList(deliveryOrder), NearbyDeliveryOrder.class);
        if (deliveryOrder == null) throw new RuntimeException("配送订单不存在");
        // 去订单模块查询订单信息
        OrderDetailForDeliveryOrderDetailVO orderDetailForDeliveryOrderDetailVO = TypeR.extract(orderFeignService.orderDetailForDeliveryOrderDetail(deliveryOrder.getOrderId()));
        // deliveryOrder + orderDetailForDeliveryOrderDetailVO 转换为 DeliveryOrderDetailsVO
        DeliveryOrderDetailsVO deliveryOrderDetailsVO = PropertiesCopy.type(Object.class, DeliveryOrderDetailsVO.class)
                .produce(new Object[]{deliveryOrder, orderDetailForDeliveryOrderDetailVO});
        return deliveryOrderDetailsVO;
    }

    @Override
    public RiderDeliveryFeeForRiderOrderAccounting queryRiderDeliveryFeeForRiderOrderAccounting(Long orderId) {
        RiderDeliveryFeeForRiderOrderAccounting riderDeliveryFeeForRiderOrderAccounting = this.baseMapper.queryRiderDeliveryFeeForRiderOrderAccounting(orderId);
        if (riderDeliveryFeeForRiderOrderAccounting == null) {
            throw new RuntimeException("该订单不存在配送订单！");
        }
        return riderDeliveryFeeForRiderOrderAccounting;
    }


    private Set<ShopForMap> computeNavigationSortAttribute(GeoCoordinates riderGeo, PathPlanningResultBuilder pathPlanningResultBuilder) {
        Map<ShopForMap, List<DinersForMap>> resultOperation = pathPlanningResultBuilder.getResultOperation();
        if (resultOperation == null || resultOperation.isEmpty()) return new HashSet<>();
        // 未送达的订单
        Set<DinersForMap> waitDeliveryOrderList = new HashSet<>();
        // 这里涉及到进行元素删除操作，所以需要拷贝一份出来
        // 使用waitReachShopList初始化waitDeliveryOrderList
        Iterator<Map.Entry<ShopForMap, List<DinersForMap>>> iterator = resultOperation.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<ShopForMap, List<DinersForMap>> shopForMapListEntry = iterator.next();
            ShopForMap currentShopForMap = shopForMapListEntry.getKey();
            List<DinersForMap> dinersList = resultOperation.get(currentShopForMap);
            if (dinersList.isEmpty()) continue;
            Iterator<DinersForMap> dinersForMapListIterator = dinersList.iterator();
            while (dinersForMapListIterator.hasNext()) {
                DinersForMap dinersForMap = dinersForMapListIterator.next();
                if (!dinersForMap.getIsWaitFetch()) {
                    // 该订单当前已取未送达
                    waitDeliveryOrderList.add(dinersForMap);
                    // 余下的ShopForMap的DinersForMap列表只剩下需要取来的
                    dinersForMapListIterator.remove();
                    // 如果ShopForMap的DinersForMap列表为空，则从resultOperation中移除
                    if (dinersList.isEmpty()) iterator.remove();
                }
            }
        }

        // 到这里resultOperation剩下未到达的店铺-待送餐列表
        Set<ShopForMap> waitReachShopList = resultOperation.keySet();

        while (!waitReachShopList.isEmpty() || !waitDeliveryOrderList.isEmpty()) {
            if (waitReachShopList.isEmpty()) {
                // 剩下的都是待配送 - 进行对waitDeliveryOrderList全部规划
                // 次选但快的-最近算法
                recentAlgorithmsMaintenanceSort(riderGeo, waitDeliveryOrderList, pathPlanningResultBuilder);
                break;
            }
            if (waitDeliveryOrderList.isEmpty()) {
                // 没有可配送的，需要先到店取餐
                // 1、获取最近的店铺-到达
                ShopForMap recentShopForMap = GeoCoordinateUtils.findRecent(riderGeo, waitReachShopList);
                riderGeo = recentShopPostProcess(resultOperation, recentShopForMap, waitDeliveryOrderList, pathPlanningResultBuilder);

            } else {
                // 找包含店铺与可配送的订单最近的
                GeoCoordinates recent = GeoCoordinateUtils.findRecent(riderGeo, waitReachShopList, waitDeliveryOrderList);
                if (recent instanceof ShopForMap) {
                    riderGeo = recentShopPostProcess(resultOperation, (ShopForMap) recent, waitDeliveryOrderList, pathPlanningResultBuilder);
                } else {
                    // 从waitDeliveryOrderList中移除
                    waitDeliveryOrderList.remove((DinersForMap) recent);
                    // put顺序
                    pathPlanningResultBuilder.putSort((DinersForMap) recent);
                    riderGeo = recent;
                }
            }
        }
        return pathPlanningResultBuilder.buildResult();

    }

    private void recentAlgorithmsMaintenanceSort(GeoCoordinates riderGeo, Set<DinersForMap> waitDeliveryOrderList, PathPlanningResultBuilder pathPlanningResultBuilder) {
        while (!waitDeliveryOrderList.isEmpty()) {
            DinersForMap recent = GeoCoordinateUtils.findRecent(riderGeo, waitDeliveryOrderList);
            pathPlanningResultBuilder.putSort(recent);
            waitDeliveryOrderList.remove(recent);
            riderGeo = recent;
        }
    }

    /**
     * 找到最近店铺之后-后期处理
     *
     * @param resultOperation           结果运算
     * @param recentShopForMap          最近地图商店
     * @param waitDeliveryOrderList     等待交货订单列表
     * @param pathPlanningResultBuilder 路径规划结果生成器
     * @return {@link GeoCoordinates}
     */
    private static GeoCoordinates recentShopPostProcess(Map<ShopForMap, List<DinersForMap>> resultOperation, ShopForMap recentShopForMap, Set<DinersForMap> waitDeliveryOrderList, PathPlanningResultBuilder pathPlanningResultBuilder) {
        // 1、从resultOperation中移除 ,waitReachShopList与resultOperation同步
        List<DinersForMap> dinersForMapInMap = resultOperation.remove(recentShopForMap);
        // 2、从对应的map中释放出diners到waitDeliveryOrderList
        waitDeliveryOrderList.addAll(dinersForMapInMap);
        // put顺序
        pathPlanningResultBuilder.putSort(recentShopForMap.getId());
        return recentShopForMap;
    }


    /**
     * 计算骑手配送单收益
     *
     * @param shopForRider 骑手商店
     * @param deliveryInfo 个人名片
     * @return {@link BigDecimal}
     */
    private BigDecimal calculateIncome(ShopForRider shopForRider, DeliveryInfo deliveryInfo) {
        // 相距的公里数
        double distance = GeoCoordinateUtils.calculateDistance(shopForRider.getLongitude(), shopForRider.getLatitude(), deliveryInfo.getLongitude(), deliveryInfo.getLatitude());
        return DeliveryCostCalculator.calculateDeliveryCost(distance);
    }


    @Override
    public DeliveryOrderForUserOrderMapVO deliveryInfoForUserOrderMap(Long orderId) {
        return this.baseMapper.selectDeliveryInfoForUserOrderMap(orderId);
    }


    @Override
    public void notifyRiderLocation(Long riderId, GeoCoordinates riderGeo) {
        // 获取骑手已接单但未完成的订单的用户ids
        List<Long> userIds = this.baseMapper.queryRiderUnfinishedDeliveryOrderUserIds(riderId, DeliveryOrderState.RIDER_RECEIVED_ORDER.getValue(),DeliveryOrderState.RIDER_PICKED_UP.getValue());
        if (userIds == null || userIds.isEmpty()) return;
        // 通知用户
        RiderLocationUpdateDTO riderLocationUpdateDTO = new RiderLocationUpdateDTO();
        riderLocationUpdateDTO.setUserIds(userIds);

        RiderLocation riderLocation = new RiderLocation();
        riderLocation.setRiderId(riderId);
        riderLocation.setLatitude(riderGeo.getLatitude());
        riderLocation.setLongitude(riderGeo.getLongitude());

        riderLocationUpdateDTO.setRiderLocation(riderLocation);
        orderFeignService.riderLocationUpdate(riderLocationUpdateDTO);
    }
}
